package com.hllxd.hism.star.basic.service.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 进行数据缓存管理，缓存的时间5分钟，返回结果会显示是否命中cached
 * @author xiyong.lxy
 * @date 2018-9-5 8:28
 */
@Component
@Slf4j
public class OneLevelCached {

    /** 1-使用  2-不聪cached返回 */
    private volatile char IS_USED=1;

    private final static Long TIMEOUT_MS = 60000L;
    /** 缓存池子 */
    private Map<String,ObjectEntity> cached = new HashMap<>();
    private LinkedBlockingQueue<String> keyInout = new LinkedBlockingQueue<>();
    private final static Long CACHED_MAX_SIZE = 300L;
//    private ReadWriteLock readWriteLock = new ReadWriteLock();

    public static class ObjectEntity {
        public long ts;
        public Object obj;

        public ObjectEntity(Object obj) {
            this.obj = obj;
            this.ts = System.currentTimeMillis();
        }
    }

    private boolean isTimeout(long ts) {
        long curr = System.currentTimeMillis();
        return curr>(ts+TIMEOUT_MS);
    }
    private void remove(String key) {
        cached.remove(key);
        while (true) {
            // 删除key之前加入内存的数据
            String t = keyInout.poll();
            if(t==null || t.equals(key)) {
                break;
            }
            cached.remove(key);
        }
    }
    private void freeOne() {
        String k = keyInout.poll();
        if(k==null) {
            return ;
        }
        cached.remove(k);
    }

    public synchronized Object get(String key) {
        ObjectEntity entity = cached.get(key);
        if(entity==null) {
            return null;
        }
        if(isTimeout(entity.ts)) {
            remove(key);
            return null;
        }
        if(IS_USED!=1) {
            // 读取不从cached返回
            return null;
        }
        return entity.obj;
    }
    public synchronized boolean set(String key, Object value) {
        if(cached.size()>CACHED_MAX_SIZE) {
            log.warn("cached is full, will free ...");
            freeOne();
        }
        if(value!=null) {
            keyInout.add(key);
            cached.put(key, new ObjectEntity(value));
            return true;
        }
        return false;
    }
}
